// StateRouter.java
package org.zjx.core.router;

import org.zjx.core.*;
import org.zjx.core.state.StateAccessor;
import org.zjx.core.state.StateComponent;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Predicate;

/**
 * 状态路由决策节点
 *
 * 这个类实现了一个状态路由决策节点，根据当前状态快照选择合适的决策树进行决策。
 * 支持基于单一状态类型的状态映射和基于复合状态条件的复合状态路由。
 */
public class StateRouter implements DecisionNode {
    // 状态映射表，键为状态类型，值为对应的决策树
    private final Map<Class<? extends StateComponent>, DecisionTree> stateMapping;
    // 状态优先级表，键为状态类型，值为优先级
    private final Map<Class<? extends StateComponent>, Integer> priorities;
    // 复合状态条件列表，每个条件包含一个谓词、决策树和优先级
    private final List<ConditionalTree> conditionalTrees;

    /**
     * 复合状态条件内部类
     *
     * 包含一个谓词用于判断状态快照是否满足条件、一个决策树用于决策、一个优先级用于排序。
     */
    private static class ConditionalTree {
        final Predicate<StateAccessor> condition;
        final DecisionTree tree;
        final int priority;

        ConditionalTree(Predicate<StateAccessor> condition,
                        DecisionTree tree,
                        int priority) {
            this.condition = condition;
            this.tree = tree;
            this.priority = priority;
        }
    }

    /**
     * 构造函数
     *
     * 初始化状态映射表、优先级表和复合状态条件列表。
     */
    public StateRouter() {
        this.stateMapping = new ConcurrentHashMap<>();
        this.priorities = new ConcurrentHashMap<>();
        this.conditionalTrees = new CopyOnWriteArrayList<>();
    }

    /**
     * 决策方法
     *
     * 在决策过程中，首先检查复合状态条件（按优先级降序），如果满足条件则使用对应的决策树进行决策。
     * 如果没有满足的复合状态条件，则检查基础状态映射（按优先级降序），使用对应的决策树进行决策。
     *
     * @param context 决策上下文，包含当前状态和调用栈等信息
     * @return 返回的GameAction，如果找到合适的决策树则返回其决策结果，否则返回null
     */
    @Override
    public GameAction decide(DecisionContext context) {

        // 1. 检查复合状态条件（按优先级降序）
        Optional<GameAction> compositeAction = conditionalTrees.stream()
                .sorted(Comparator.comparingInt(ct -> -ct.priority))
                .filter(ct -> ct.condition.test(context.getStateAccessor()))
                .findFirst()
                .map(ct -> ct.tree.decide(context));

        if (compositeAction.isPresent()) {
            return compositeAction.get();
        }

        // 2. 检查基础状态映射（按优先级降序）
        return stateMapping.entrySet().stream()
                .filter(e -> context.getStateAccessor().getComponent(e.getKey()).isPresent())
                .max(Comparator.comparingInt(e -> priorities.getOrDefault(e.getKey(), 0)))
                .map(e -> e.getValue().decide(context))
                .orElse(null);
    }

    /**
     * 构建器方法：添加单一状态类型的决策树
     *
     * @param stateType 状态类型
     * @param tree 对应的决策树
     * @return 当前StateRouter实例，支持链式调用
     */
    public StateRouter withState(Class<? extends StateComponent> stateType,
                                 DecisionTree tree) {
        return withState(stateType, tree, 0);
    }

    /**
     * 构建器方法：添加单一状态类型的决策树（带优先级）
     *
     * @param stateType 状态类型
     * @param tree 对应的决策树
     * @param priority 优先级
     * @return 当前StateRouter实例，支持链式调用
     */
    public StateRouter withState(Class<? extends StateComponent> stateType,
                                 DecisionTree tree, int priority) {
        stateMapping.put(stateType, tree);
        priorities.put(stateType, priority);
        return this;
    }

    /**
     * 构建器方法：添加复合状态条件的决策树
     *
     * @param condition 复合状态条件谓词
     * @param tree 对应的决策树
     * @return 当前StateRouter实例，支持链式调用
     */
    public StateRouter withCompositeState(Predicate<StateAccessor> condition,
                                          DecisionTree tree) {
        return withCompositeState(condition, tree, 0);
    }

    /**
     * 构建器方法：添加复合状态条件的决策树（带优先级）
     *
     * @param condition 复合状态条件谓词
     * @param tree 对应的决策树
     * @param priority 优先级
     * @return 当前StateRouter实例，支持链式调用
     */
    public StateRouter withCompositeState(Predicate<StateAccessor> condition,
                                          DecisionTree tree, int priority) {
        conditionalTrees.add(new ConditionalTree(condition, tree, priority));
        return this;
    }
}